package de.projectgoodmorning.alarm;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

/**
 * Der BTController ist die Schnittstelle zum Bluetooths-Adapter. 
 * Verbindungen zu anderen Bluetoothgeraeten uebernimmt diese Klasse.
 * 
 * Der BTController ist als Service umgesetzt. Somit ist der BTController
 * immer aktiv (nach der ersten Ausfuehrung) und bereit zum Senden von Signalen,
 * auch wenn die Anwendung bereits vom System gestoppt wurde.
 */
public class BTController extends Service {
	private static final String TAG = BTController.class.getName();
	
	private final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
	private String currentMAC;
	private boolean connected = false;
	
	private BluetoothAdapter localAdapter = BluetoothAdapter.getDefaultAdapter();
	private BluetoothDevice btDevice;
	private BluetoothSocket btSocket;

	private InputStream inputStream;
	private OutputStream outputStream;

	/**
	 * gibt den OutputStream des Bluetooth-Sockets zurueck
	 */
	public OutputStream getOutputStream() {
		return outputStream;
	}

	/**
	 * gibt den InputStream des Bluetooth-Sockets zurueck
	 */
	public InputStream getInputStream() {
		return inputStream;
	}
	
	/**
	 * gibt an, ob noch eine Verbindung zum Geraet besteht.
	 * @return		gibt true wenn verbunden, sonst false
	 */
	public boolean isConnected() {
		return connected;
	}
	
	/**
	 * verbindet sich mit einem Bluetoothgeraet anhand dessen BT-Mac-Adresse
	 * @param deviceMAC			erwartet die Bluetooth-Mac-Adresse
	 * @throws IOException		wenn Verbindung zum Socket nicht aufgebaut werden kann.
	 */
	public void connect( String deviceMAC ) throws IOException {
		if( localAdapter == null ) {
			return;
		}
		
		if( isConnected() ) {
			close();
		}
		
		currentMAC = deviceMAC;
		
		btDevice = localAdapter.getRemoteDevice( deviceMAC );
		btSocket = btDevice.createRfcommSocketToServiceRecord( uuid );

		btSocket.connect();
		
		outputStream = btSocket.getOutputStream();
		inputStream = btSocket.getInputStream();
		
		connected = true;
		Log.d( TAG, "connected to " + deviceMAC );
	}
	
	/**
	 * versucht sich erneut zum letzten Geraet zu verbinden.
	 * @throws IOException				wenn Verbindung zum Socket nicht 
	 * 									aufgebaut werden kann.
	 * @throws IllegalStateException	wenn zuvor keine Verbindung erstellt wurde
	 */
	public void reconnect() throws IOException {
		if( currentMAC != null ) {
			connect( currentMAC );
		} else {
			throw new IllegalStateException( "No previous connection." );
		}
	}
	
	/**
	 * schliesst die Verbindung
	 */
    public void close() {
    	connected = false;
    	
    	if( btSocket != null ) {
			try {
				btSocket.close();
				Log.d( TAG, "disconnected from " + currentMAC );
			} catch (IOException e) {
	
			}
    	}
    }
	
    /**
     * gibt an, ob der Bluetooth-Adapter eingeschaltet ist.
     * @return		gibt true wenn ein, sonst false
     */
	public boolean isEnabled() {
		if( localAdapter == null ) {
			return false;
		}
		
		return localAdapter.isEnabled();
	}
	
	/**
	 * gibt Informationen vom verbundenen Geraet zurueck.
	 * (Mac-Adresse, Name ...)
	 */
	public BluetoothDevice getConnectedDevice() {
		return btDevice;
	}

	/**
	 * schaltet den Bluetooth-Adapater ein.
	 */
	public void enable() {
		if( !isEnabled() ) {
			localAdapter.enable();
		}
	}
	
	@Override
	public boolean onUnbind( Intent intent ) {
		boolean ret = super.onUnbind( intent );
		
		if( !isConnected() ) {
			stopSelf();
		}
		
		return ret; 
	}
	
	/////////////////////// SERVICE ///////////////////////////
	
    public class LocalBinder extends Binder {
    	public BTController getService() {
            return BTController.this;
        }
    }		
	
	private final IBinder binder = new LocalBinder();
	@Override
	public IBinder onBind( Intent intent ) {
		return binder;
	}
}